package LuceneIndexCreate;

import com.alibaba.fastjson.JSON;
import lucene.IKAnalyzer5x.IKAnalyzer5x;
import lucene.IKAnalyzer5x.IKSynonymsAnalyzer5x;
import LuceneIndexCreate.model.CatIndexData;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.*;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.*;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.springframework.util.StringUtils;

import java.io.*;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Created by User on 2017/12/7.
 */
public class LuceneIndex {

    public static String indexPath = "E:\\lucene\\index13_1";

    public static Directory directory = null;

    public static IKAnalyzer5x analyzer = new IKAnalyzer5x(true);

    static {
        try {
            directory = FSDirectory.open(Paths.get(indexPath));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws IOException, ParseException, InterruptedException {
//        long start = System.currentTimeMillis();
//        searchIndex("联想笔记本电脑,笔记本电脑,联想电脑,联想笔记本电脑");
//        searchIndex("直销商务小本子,定制日记本,直销小本子,办公小本子,商务小本子");
//        searchIndex("Petstyle 2017秋冬新款 5号双蝴蝶结小香棉裙 宠物衣服 狗狗服装");
//        searchIndex("大型犬衣服^2,大型犬战术衣服^1,警犬衣服^1,军犬训练装备^1,训练装备^1");
//        searchIndex("定做校服^2,定制短袖t恤^1,定做班校服^1,毕业聚会衣服^1,短袖t恤^1");
//        searchIndex("平底马丁靴,欧美马丁靴,新款马丁靴,欧美平底马丁靴,系带女靴");
//        searchIndex("新款女装,五四学生装,五四青年女装,演出礼服,青年女装");


        String keyword = GetDesc.getDesc("562466163680", 3);
        System.out.println(keyword);
        searchIndex(keyword);


//50007068
//        long end = System.currentTimeMillis();
//        System.out.println("耗时" + (end - start) + "ms");

//        fixIndex("50005207");
//        fixIndex("50013618");

//        Document document = selectIndex("50011743");
//        printDocument(document);

//        searchIndex("女");

//        deleteIndex("50009579", "50009580", "50009581");


//        updateIndex("50008898", "女装/女士精品-->卫衣/绒衫", "套头卫衣,丝绒套头卫衣,刺绣上衣,时尚上衣,加厚上衣");

//        for (int i = 0; i < 110; i++) {
//            long s = System.currentTimeMillis();
//            buildIndex("E:\\lucene\\索引数据1\\测试"+i+".txt");
//            long e = System.currentTimeMillis();
//
//            System.out.println("第" +i+ "页索引创建完成 耗时" + (e - s) + "ms");
//        }

    }

    public static void fixBookIndex() throws IOException {
//        List<Map> exec = DB.exec("select * from item_cat_lucene2 where nnn like '%书籍/杂志/报纸%'");
        List<Map> exec = DB.exec("select * from item_cat_lucene2 where nnn like '%运动/瑜伽/健身/球迷用品-->马术运动-->马球用品%'");

        for (Map map : exec) {
            System.out.println(1);
            Object cid = map.get("cid");
            fixIndex(String.valueOf(cid));
        }

    }

    // 索引男女关键字权重修复
    public static void fixGender() throws IOException {

        IndexReader indexReader = DirectoryReader.open(directory);
        IndexSearcher indexSearcher = new IndexSearcher(indexReader);

        Query query = new WildcardQuery(new Term("name", "*男*"));
        TopDocs search = indexSearcher.search(query, 99999);

        int totalHits = search.totalHits;
        for (int i = 0; i < totalHits; i++) {
            ScoreDoc scoreDoc = search.scoreDocs[i];
            Document doc = indexSearcher.doc(scoreDoc.doc);
            printDocument(doc);
            updateIndex(doc.get("cid"), doc.get("name"), "男,男,男,男,男");
        }

        indexReader.close();

        indexReader = DirectoryReader.open(directory);
        indexSearcher = new IndexSearcher(indexReader);

        query = new WildcardQuery(new Term("name", "*女*"));
        search = indexSearcher.search(query, 99999);

        totalHits = search.totalHits;
        for (int i = 0; i < totalHits; i++) {
            ScoreDoc scoreDoc = search.scoreDocs[i];
            Document doc = indexSearcher.doc(scoreDoc.doc);
            printDocument(doc);
            updateIndex(doc.get("cid"), doc.get("name"), "女,女,女,女,女");
        }

        indexReader.close();

    }

    // 初始化desc不符合类目的索引
    public static void fixIndex(String cid) throws IOException {
        // 查询之前cid对应的索引信息
        Document document = selectIndex(cid);
        if (document == null) return;
        String name = document.get("name");
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 15 && sb.length() < 200; i++) {
            sb.append(name.replaceAll("-->|/", " ")).append(",");
        }
        String fixDesc = sb.toString();

        IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);
        IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig);

        Document documentUpdate = new Document();
        documentUpdate.add(new TextField("cid", cid, Field.Store.YES));
        documentUpdate.add(new TextField("name", name, Field.Store.YES));
        documentUpdate.add(new TextField("desc", fixDesc, Field.Store.YES));

        indexWriter.updateDocument(new Term("cid", cid), documentUpdate);

        indexWriter.close();


    }

    public static void buildIndex(String filePath) throws IOException {
        File file = new File(filePath);
        BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));

        String line = null;
        while ((line = reader.readLine()) != null) {
            CatIndexData catIndexData = JSON.parseObject(line, CatIndexData.class);
            String cid = catIndexData.getCid();
            String keyword = catIndexData.getKeyword();
            String desc = catIndexData.getDesc();
            if (desc == null || "".equals(desc.trim())) continue;
            // 索引描述里添加15次keyword 或 100字符
            String realKeyword = DB.getRealKeyword(cid);
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < 15 && sb.length() < 200; i++) {
                sb.append(realKeyword.replaceAll("-->|/", " ")).append(",");
            }
            sb.append(desc);
            createIndex(cid, realKeyword, sb.toString());
            //System.out.printf("成功创建索引耗时%sms %s %n", end - start, line);
        }

        reader.close();
    }

    public static void searchIndex(String keyword) throws IOException, ParseException {

        keyword = weightProcess(keyword);

        IndexReader indexReader = DirectoryReader.open(directory);

        IndexSearcher indexSearcher = new IndexSearcher(indexReader);

        QueryParser parser = new QueryParser("desc", new IKSynonymsAnalyzer5x());

        Query query = parser.parse(keyword);

        System.out.println(query.toString());

        TopDocs topDocs = indexSearcher.search(query, 7);

        System.out.println("查询结果总记录数：" + topDocs.totalHits);

        for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
            int docId = scoreDoc.doc;
            Document document = indexSearcher.doc(docId);
            List<IndexableField> fields = document.getFields();

            System.out.println("得分:" + scoreDoc.score);
            printDocument(document);
        }

        indexReader.close();
    }

    public static List<Document> searchDocument(String keyword) throws IOException, ParseException {

        keyword = weightProcess(keyword);

        List<Document> list = new ArrayList<>();

        IndexReader indexReader = DirectoryReader.open(directory);

        MultiReader multiReader = new MultiReader(indexReader);

        IndexSearcher indexSearcher = new IndexSearcher(multiReader);

        QueryParser parser = new QueryParser("desc", new IKSynonymsAnalyzer5x());

        Query query = parser.parse(keyword);

        TopDocs topDocs = indexSearcher.search(query, 5);

        for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
            int docId = scoreDoc.doc;
            Document document = indexSearcher.doc(docId);
            list.add(document);
        }

        indexReader.close();

        return list;
    }

    private static String weightProcess(String keyword) throws IOException {
        if (StringUtils.isEmpty(keyword)) return keyword;
        String[] aWord = keyword.split(",");
        int length = aWord.length;
        // 设置第一个词语的权重
        if (length > 2) {
            aWord[0] += "^2";
        }

        String result = String.join(",", aWord);

        /*// 增加男女关键字的权重
        if (keyword.contains("男") || keyword.contains("女")) {
            if (keyword.contains("男") && keyword.contains("女")) {
                ;
            } else {
                // 含有男女关键其中一个
                TokenStream tokenStream = analyzer.tokenStream("content", keyword);
                OffsetAttribute offsetAttribute = tokenStream.addAttribute(OffsetAttribute.class);
                tokenStream.reset();
                while (tokenStream.incrementToken()) {
                    String splitWord = offsetAttribute.toString();
                    if (splitWord.contains("女") || splitWord.contains("男")) {
                        result += " " + splitWord + "^" + (length - 1);
                        break;
                    } else {
                        ;
                    }
                }
                tokenStream.close();
            }
        }*/

        return result;
    }

    public static void createIndex(String cid, String name, String desc) throws IOException {

        IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);

        IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig);

        Document document = new Document();
        document.add(new TextField("cid", cid, Field.Store.YES));
        document.add(new TextField("name", name, Field.Store.YES));
        document.add(new TextField("desc", desc, Field.Store.YES));

        indexWriter.addDocument(document);

        indexWriter.close();
    }

    public static void updateIndex(String cid, String name, String desc) throws IOException {

        // 查询之前cid对应的索引信息
        Document document = selectIndex(cid);
        String oldDesc = "";
        if (document != null) oldDesc = document.get("desc");

        IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);
        IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig);

        Document documentUpdate = new Document();
        documentUpdate.add(new TextField("cid", cid, Field.Store.YES));
        documentUpdate.add(new TextField("name", name, Field.Store.YES));
        documentUpdate.add(new TextField("desc", oldDesc + desc, Field.Store.YES));

        indexWriter.updateDocument(new Term("cid", cid), documentUpdate);

        indexWriter.close();
    }

    public static void deleteIndex(String... cid) throws IOException {

        for (String acid : cid) {
            IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);
            IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig);

            indexWriter.deleteDocuments(new Term("cid", acid));

            indexWriter.close();
        }
    }

    public static Document selectIndex(String cid) throws IOException {

        IndexReader indexReader = DirectoryReader.open(directory);

        IndexSearcher indexSearcher = new IndexSearcher(indexReader);

        Query query = new TermQuery(new Term("cid", cid));

        TopDocs topDocs = indexSearcher.search(query, 10);

        if (topDocs.totalHits == 0) {
            System.out.println("未找到对应索引 --> " + cid);
            return null;
        } else if (topDocs.totalHits == 1) {
            ScoreDoc scoreDoc = topDocs.scoreDocs[0];
            Document document = indexSearcher.doc(scoreDoc.doc);
            return document;
        } else {
            System.out.println("出现重复索引");
            throw  new RuntimeException("出现重复索引");
        }
    }

    public static void printDocument(Document document) {
        if (document != null) {
            System.out.println("====================================");
            System.out.println("cid:" + document.get("cid"));
            System.out.println("name:" + document.get("name"));
            System.out.println("desc:" + document.get("desc"));
            System.out.println("====================================");
        }
    }

    public static void doReplaceIndex() throws IOException {
        File file;
        file = new File("E:\\lucene\\索引数据2\\流行男鞋.txt");
        file = new File("E:\\lucene\\索引数据2\\男装.txt");
        file = new File("E:\\lucene\\索引数据2\\女鞋.txt");
        file = new File("E:\\lucene\\索引数据2\\女装_女士精品.txt");
        file = new File("E:\\lucene\\索引数据2\\童装童鞋亲子装.txt");

        BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));

        String line = null;
        while ((line = reader.readLine()) != null) {
            CatIndexData catIndexData = JSON.parseObject(line, CatIndexData.class);
            String cid = catIndexData.getCid();
            String keyword = catIndexData.getKeyword();
            String desc = catIndexData.getDesc();
            if (desc == null || "".equals(desc.trim()))
            if (desc == null || "".equals(desc.trim())) continue;
            // 索引描述里添加15次keyword 或 100字符
            String realKeyword = DB.getRealKeyword(cid);
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < 10; i++) {
                sb.append(realKeyword.replaceAll("-->|/", " ")).append(",");
            }
            sb.append(desc);
            replaceIndex(cid, realKeyword, sb.toString());
        }
        reader.close();
    }

    public static void replaceIndex(String cid, String name, String desc) throws IOException {
        // 查询之前cid对应的索引信息
        Document document = selectIndex(cid);
        if (document != null) {
            IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);
            IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig);
            Document documentUpdate = new Document();
            documentUpdate.add(new TextField("cid", cid, Field.Store.YES));
            documentUpdate.add(new TextField("name", name, Field.Store.YES));
            documentUpdate.add(new TextField("desc", desc, Field.Store.YES));
            indexWriter.updateDocument(new Term("cid", cid), documentUpdate);
            indexWriter.close();
        } else {
            createIndex(cid, name, desc);
        }
    }
}
